#ifndef __FREE_LIST_H__
#define __FREE_LIST_H__

#include <stdexcept>
#include <list>
#include <algorithm>
#include <new>

#ifndef ASSERT
	#ifdef _DEBUG
		#include <assert.h>
		#define ASSERT(x) assert(x)
	#else
		#define ASSERT(x) 
	#endif
#endif

template<class T, size_t BufferSize = 1024>
class FreeList
{
private:
	T* _buffer;
	std::list<int> _freelist;
public:
	FreeList() {
		_buffer = (T*)new char[sizeof(T) * BufferSize];
		clear();
	}
	~FreeList() {
		ASSERT(full() && "not release all");
		free(_buffer);
	}
	size_t size() const { return BufferSize - _freelist.size(); }
	size_t capacity() const { return BufferSize; }
	bool empty() const { return _freelist.empty(); }
	bool full() const { return _freelist.size() >= capacity(); }
	void clear() { 
		for (int i = 0; i < BufferSize; i++) {
			_freelist.push_back(i);
		}
	}

	T* get() {
		ASSERT(!empty() && "full");
		int index = _freelist.front();
		_freelist.pop_front();
		return new(&_buffer[index]) T;
	}

	void recycle(T* item) {		
		item->~T();
		int index = (item - _buffer);
		ASSERT(index < BufferSize && "full");
		ASSERT(std::find(_freelist.begin(), _freelist.end(), index) == _freelist.end() && "Pop empty");
		_freelist.push_back(index);
	}
};

#endif //__FREE_LIST_H__